Lær hvordan du effektivt organiserer dine Django REST Framework API-er med ViewSets. Denne guiden dekker alt fra grunnleggende bruk til avansert tilpasning, med eksempler og beste praksis.
Django REST Framework ViewSets: Mestring av API-endepunktorganisering
I moderne webutvikling er det avgjørende å bygge robuste og velsmurte API-er. Django REST Framework (DRF) er et kraftig verktøy for å lage RESTful API-er med Django. Mens DRF tilbyr ulike verktøy for å lage API-endepunkter, gir ViewSets en elegant måte å organisere relaterte visninger i en enkelt klasse, noe som fører til renere og mer vedlikeholdbar kode. Denne omfattende guiden vil utforske ViewSets i detalj, og dekke deres fordeler, bruk og avanserte tilpasningsteknikker.
Hva er ViewSets?
En ViewSet er en klassebasert visning som gir implementeringer for standardoperasjoner, som list
, create
, retrieve
, update
og destroy
. I stedet for å definere separate visninger for hver operasjon, kombinerer en ViewSet dem i en enkelt klasse, noe som forenkler API-strukturen og reduserer kodeduplisering. ViewSets er spesielt nyttige når du arbeider med modellbaserte API-er, der disse standardoperasjonene ofte er nødvendige. Tenk på en ViewSet som en logisk gruppering av operasjoner på en spesifikk ressurs.
Fordeler med å bruke ViewSets
- Gjenbrukbar kode: ViewSets fremmer gjenbruk av kode ved å innkapsle felles API-logikk i en enkelt klasse. Dette reduserer redundans og gjør koden lettere å vedlikeholde.
- Forenklet ruting: ViewSets forenkler ruting ved å gruppere relaterte visninger under et enkelt URL-prefiks. Dette resulterer i en renere og mer organisert URL-struktur.
- Redusert standardkode: ViewSets reduserer standardkode ved å tilby standardimplementeringer for vanlige API-operasjoner. Dette gjør at utviklere kan fokusere på å implementere tilpasset logikk spesifikt for applikasjonen deres.
- Forbedret lesbarhet: ViewSets forbedrer kodelesbarheten ved å organisere relaterte visninger i en enkelt klasse. Dette gjør API-strukturen lettere å forstå og navigere.
- Konsistens: ViewSets bidrar til å sikre konsistens på tvers av API-et ved å håndheve et standard sett med operasjoner og konvensjoner. Dette gjør API-et mer forutsigbart og lettere å bruke.
Grunnleggende bruk av ViewSets
La oss starte med et enkelt eksempel på hvordan du bruker ViewSets til å lage et API for administrasjon av produkter. Først definerer du en modell:
# models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
def __str__(self):
return self.name
Deretter definerer du en serializer for Product
-modellen:
# serializers.py
from rest_framework import serializers
from .models import Product
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
Nå oppretter du en ViewSet for Product
-modellen:
# views.py
from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
Til slutt konfigurerer du URL-rutingen:
# urls.py
from django.urls import path, include
from rest_framework import routers
from . import views
router = routers.DefaultRouter()
router.register(r'products', views.ProductViewSet)
urlpatterns = [
path('', include(router.urls)),
]
Denne konfigurasjonen vil automatisk generere følgende API-endepunkter:
/products/
(GET: liste, POST: opprett)/products/{id}/
(GET: hent, PUT: oppdater, PATCH: delvis_oppdater, DELETE: slett)
ModelViewSet
tilbyr standardimplementeringer for alle standard CRUD-operasjoner. Attributten queryset
spesifiserer settet med objekter som ViewSet skal operere på, og attributten serializer_class
spesifiserer serializeren som skal brukes for serialisering og deserialisering av data.
Typer ViewSets
DRF tilbyr flere innebygde ViewSet-klasser som passer til forskjellige bruksområder:
ViewSet
: Grunnklassen for alle ViewSets. Den gir den grunnleggende infrastrukturen for å håndtere forespørsler og svar.ReadOnlyModelViewSet
: En ViewSet som gir skrivebeskyttede operasjoner (list
ogretrieve
). Dette er nyttig for API-er som kun tillater datainnhenting.ModelViewSet
: En ViewSet som gir alle standard CRUD-operasjoner (list
,create
,retrieve
,update
ogdestroy
). Dette er den mest brukte ViewSet for modellbaserte API-er.GenericViewSet
: En ViewSet som gir en generisk implementering for vanlige API-operasjoner. Dette kan brukes som en grunnklasse for å lage tilpassede ViewSets.
Valg av riktig ViewSet avhenger av de spesifikke kravene til API-et ditt. Hvis du bare trenger skrivebeskyttede operasjoner, bruk ReadOnlyModelViewSet
. Hvis du trenger alle standard CRUD-operasjoner, bruk ModelViewSet
. Hvis du trenger mer kontroll over API-atferden, kan du lage en tilpasset ViewSet ved å arve fra GenericViewSet
eller ViewSet
.
Tilpasning av ViewSets
Selv om de innebygde ViewSets gir en praktisk måte å lage API-er på, kan det hende du må tilpasse atferden deres for å møte spesifikke krav. DRF tilbyr flere måter å tilpasse ViewSets på, inkludert å overstyre metoder, legge til egendefinerte handlinger og bruke egendefinerte serializere.
Overstyre metoder
Du kan overstyre standardimplementeringene av standard API-operasjoner ved å definere metoder med samme navn i ViewSet-klassen din. For eksempel kan du overstyre create
-metoden for å legge til tilpasset logikk før eller etter opprettelse av et nytt objekt:
# views.py
from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer
from rest_framework.response import Response
from rest_framework import status
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
# Add custom logic here before creating the object
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
I dette eksemplet overstyrer create
-metoden standardimplementeringen og legger til tilpasset logikk før objektet opprettes. Metoden perform_create
kalles for faktisk å opprette objektet, og svaret returneres med en 201 Created
-statuskode.
Legge til egendefinerte handlinger
Du kan legge til egendefinerte handlinger i ViewSet-en din ved hjelp av @action
-dekoratøren. Egendefinerte handlinger lar deg definere nye API-endepunkter som utfører spesifikke operasjoner på ressursene som administreres av ViewSet. For eksempel kan du legge til en handling for å markere et produkt som utvalgt:
# views.py
from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import status
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
@action(detail=True, methods=['post'])
def feature(self, request, pk=None):
product = self.get_object()
product.is_featured = True
product.save()
serializer = self.get_serializer(product)
return Response(serializer.data)
I dette eksempelet definerer @action
-dekoratøren et nytt API-endepunkt /products/{id}/feature/
som markerer et produkt som utvalgt. Argumentet detail=True
indikerer at handlingen opererer på en spesifikk forekomst av modellen. Argumentet methods=['post']
spesifiserer at handlingen kun aksepterer POST-forespørsler.
Bruke egendefinerte serializere
Du kan bruke egendefinerte serializere for å tilpasse hvordan data serialiseres og deserialiseres av ViewSet. Dette er nyttig når du trenger å håndtere komplekse datastrukturer eller utføre egendefinert validering. For eksempel kan du bruke en egendefinert serializer til å inkludere relaterte data i API-svaret:
# serializers.py
from rest_framework import serializers
from .models import Product, Category
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ['id', 'name']
class ProductSerializer(serializers.ModelSerializer):
category = CategorySerializer(read_only=True)
class Meta:
model = Product
fields = '__all__'
# views.py
from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
I dette eksempelet inkluderer ProductSerializer
en CategorySerializer
for å serialisere de relaterte kategoridataene. Dette lar deg hente kategoriinformasjonen sammen med produktinformasjonen i en enkelt API-forespørsel.
Avanserte ViewSet-teknikker
Utover grunnleggende bruk og tilpasning tilbyr ViewSets avanserte teknikker for å bygge sofistikerte API-er:
Filtrering
DRF gir kraftige filtreringsfunksjoner som lar deg filtrere spørringssettet basert på forespørselsparametere. Du kan bruke attributten filter_backends
til å spesifisere filtrerings-backends som skal brukes. For eksempel kan du bruke SearchFilter
for å la brukere søke etter produkter etter navn eller beskrivelse:
# views.py
from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer
from rest_framework import filters
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
filter_backends = [filters.SearchFilter]
search_fields = ['name', 'description']
I dette eksempelet spesifiserer attributten filter_backends
at SearchFilter
skal brukes. Attributten search_fields
spesifiserer feltene som skal søkes i.
Paginering
DRF gir pagineringsfunksjoner som lar deg dele spørringssettet inn i mindre sider. Dette er nyttig når du håndterer store datasett. Du kan bruke attributten pagination_class
til å spesifisere pagineringsklassen som skal brukes. For eksempel kan du bruke PageNumberPagination
for å paginere resultatene ved hjelp av sidetall:
# views.py
from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer
from rest_framework.pagination import PageNumberPagination
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
pagination_class = PageNumberPagination
I dette eksempelet spesifiserer attributten pagination_class
at PageNumberPagination
skal brukes. Du kan også tilpasse pagineringsatferden ved å lage din egen pagineringsklasse.
Autentisering og tillatelser
DRF gir fleksible autentiserings- og tillatelsesmekanismer som lar deg kontrollere tilgangen til API-endepunktene dine. Du kan bruke attributtene authentication_classes
og permission_classes
til å spesifisere autentiserings- og tillatelsesklassene som skal brukes. For eksempel kan du bruke TokenAuthentication
til å autentisere brukere med tokens og IsAuthenticated
-tillatelsen for å kun tillate autentiserte brukere å få tilgang til API-et:
# views.py
from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
I dette eksempelet spesifiserer attributten authentication_classes
at TokenAuthentication
skal brukes, og attributten permission_classes
spesifiserer at IsAuthenticated
-tillatelsen skal brukes.
Beste praksis for bruk av ViewSets
For å sikre at ViewSets er godt designet og vedlikeholdbare, følg disse beste praksisene:
- Hold ViewSets fokusert: Hver ViewSet bør være ansvarlig for å administrere en enkelt ressurs eller et nært beslektet sett med ressurser. Unngå å lage altfor komplekse ViewSets som håndterer flere urelaterte operasjoner.
- Bruk passende ViewSet-typer: Velg ViewSet-typen som best passer kravene til API-et ditt. Bruk
ReadOnlyModelViewSet
for skrivebeskyttede API-er,ModelViewSet
for CRUD-API-er, ogGenericViewSet
ellerViewSet
for tilpassede API-er. - Følg RESTful-prinsipper: Design API-endepunktene dine i henhold til RESTful-prinsipper. Bruk standard HTTP-metoder (GET, POST, PUT, PATCH, DELETE) for å utføre operasjoner på ressurser.
- Bruk serializere for datavalidering: Bruk serializere til å validere data som sendes til og mottas fra API-et. Dette bidrar til å sikre dataintegritet og forhindrer feil.
- Implementer riktig autentisering og tillatelser: Sikre API-endepunktene dine ved å implementere riktig autentisering og tillatelser. Dette bidrar til å beskytte dataene dine mot uautorisert tilgang.
- Skriv omfattende tester: Skriv omfattende tester for å sikre at ViewSets fungerer som de skal. Dette bidrar til å forhindre regresjoner og gjør det lettere å vedlikeholde koden.
Betraktninger om internasjonalisering (i18n) og lokalisering (l10n)
Når du bygger API-er for et globalt publikum, er det viktig å vurdere internasjonalisering (i18n) og lokalisering (l10n). ViewSets kan tilpasses for å støtte flere språk og regioner:
- Serializer-felter: Bruk DRFs serializer-felter med passende oversettelsesfunksjoner (f.eks.
gettext
fra Djangos i18n-rammeverk) for å vise oversatte feltetiketter og hjelpetekster. - Feilmeldinger: Sørg for at feilmeldinger som returneres av API-et, er oversatt til brukerens foretrukne språk.
- Dato- og tidsformatering: Bruk passende dato- og tidsformatering basert på brukerens lokalisering. DRF tilbyr alternativer for tilpasning av dato- og tidsformater.
- Valutaformatering: Formater valutaverdier i henhold til brukerens lokalisering. Vurder å bruke biblioteker som
babel
for valutaformatering. For eksempel kan en pris på 1234.56 USD formateres som $1,234.56 i USA, men som 1.234,56 $ i noen europeiske land. - Tidssoner: Håndter tidssoner riktig. Lagre datoer og tider i UTC og konverter dem til brukerens lokale tidssone når de vises.
For eksempel kan et produkt ha en beskrivelse som må oversettes. Du vil bruke Djangos oversettelsessystem i serializeren:
# serializers.py
from rest_framework import serializers
from django.utils.translation import gettext_lazy as _
from .models import Product
class ProductSerializer(serializers.ModelSerializer):
description = serializers.CharField(help_text=_("Product description"))
class Meta:
model = Product
fields = '__all__'
Og i malene dine eller koden som bruker denne serializeren, sørg for at riktig språk er aktivert.
Eksempel: E-handels-API med internasjonal støtte
Forestill deg et e-handels-API som selger produkter globalt. Product
-modellen kan inneholde felt som name
, description
, price
og image
. API-et må støtte flere språk og valutaer.
ViewSet vil håndtere de grunnleggende CRUD-operasjonene for produkter. Serializerne vil bli tilpasset for å støtte oversettelse av produktnavn og -beskrivelse. API-et vil også inkludere endepunkter for å hente produkter etter kategori, filtrere produkter etter prisklasse og søke etter produkter etter nøkkelord. Disse funksjonene må ta hensyn til internasjonalisering, spesielt rundt søkeord og produktbeskrivelser som kan variere mellom språk.
Eksempel-URL-er:
/en/products/
- Liste over produkter på engelsk/fr/products/
- Liste over produkter på fransk/en/products/?currency=USD
- Liste over produkter i USD/fr/products/123/?currency=EUR
- Detaljer om produkt 123 på fransk, pris vist i EUR
Konklusjon
Django REST Framework ViewSets gir en kraftig og elegant måte å organisere API-endepunktene dine på. Ved å innkapsle relaterte visninger i en enkelt klasse, fremmer ViewSets gjenbruk av kode, forenkler ruting og forbedrer kodelesbarheten. Med muligheten til å tilpasse ViewSets gjennom å overstyre metoder, legge til egendefinerte handlinger og bruke egendefinerte serializere, kan du skreddersy dem for å møte de spesifikke kravene til API-et ditt. Ved å følge de beste praksisene som er skissert i denne guiden, kan du sikre at ViewSets er godt designet, vedlikeholdbare og skalerbare, noe som resulterer i robuste og effektive API-er.
Husk å vurdere internasjonalisering og lokalisering når du bygger API-er for et globalt publikum. Tilpass ViewSets og serializere for å støtte flere språk, valutaer og tidssoner for å gi en sømløs opplevelse for brukere over hele verden.
Denne guiden skal tjene som et solid grunnlag for å forstå og implementere ViewSets i dine Django REST Framework-prosjekter. Fortsett å øve, eksperimentere og utforske DRF-dokumentasjonen for å bli en sann ViewSet-mester!